from stacking.instance.generation.simgen import SimGen


class SimGenIPS(SimGen):
    """Simulation-based instance generator that uses Items-Per-Stack ratio to assess the 
    difficulty of an instance. The items-per-stack ratio is simply a computation of the total 
    stay time of items in the warehouse (remember we have release and due intervals already), 
    divided by elapsed time (difference between latest due and earliest release), resulting in 
    the average number of items in the warehouse at any given time. Then, we divide this by the 
    number of stacks to compute the average of items in a stack at any given time."""
    def configure(self, target=10.0, epsilon=0.5, config_fnc=None):
        self.target = target
        self.epsilon = epsilon
        if config_fnc is not None:
            config_fnc(self)
        
    def analyze(self, items, nstacks):
        """Returns True if the given item list matches the specified IPS ratio interval. If the 
        observed ratio is too different from the target (more than the allowed epsilon), the 
        production interval is adjusted and the method returns False.""" 
        IPS = items_per_stack_ratio(items, nstacks)
        delta = abs(IPS - self.target)
        self.obs_tseries.collect(IPS)
        self.tgt_tseries.collect(self.target)
        if delta <= self.epsilon:
            return True, delta
        # adjust production interval: if the target IPS is 10x the observed value, then the 
        # "target" production interval is one tenth of the current interval in order to increase 
        # difficulty roughly 10 times.
        self.adjust_production_interval(self.production_interval * IPS / self.target)
        return False, delta
        
        
def items_per_stack_ratio(items, nstacks):
    """Computes the items-per-stack ratio of a given list of items. This value is used as an 
    estimate of instance difficulty."""
    total_stay = sum(item.min_stay for item in items)
    min_t = min(item.release.start for item in items)
    max_t = max(item.due.end for item in items)
    return float(total_stay) / ((max_t - min_t) * nstacks)
    
SimGen.IPS = SimGenIPS
